Mocking Singletons in Python

January 7, 2026
Marcus Wyche

Python supports mocking in the unittest.mock module. The other day I was trying to mock the same function across multiple tests and I couldn't figure out why the results of what came back from the mock wouldn't change from what I set it as in the first test. I banged my head against this an embarrassing long time. Going from using patch:

  • Internally across the multiple tests using with statements.
  • Using patch as a function decorator on each test.
  • Using the mocker fixture provided by pytest-mock
  • Tried to switch the test to being a unittest.TestCase so I could forcibly reset_mock in setup

None of the above would work. Finally, took a walk and started thinking about my code and realized the problem wasn't the mocking library and all the docs out there about how to use it. The problem instead was my own code and that I was trying to mock a singleton call that I had in my service. Once I realized that the problem was odvious that the mock call didn't change after the first test because the function I was trying to mock (in this case requests.get() call embedded in a function in a service that I was testing) was only being called once due to it being a SINGLETON 🤦 .

Here's an example of what was failing:

  • An example singleton call to test:

FAKE_RESULTS = None

def get_dune_character():
    """ Singleton function to get dune character(s)"""
    global FAKE_RESULTS
    if FAKE_RESULTS is None:
    # Retrieve results
    log.info("Attempting request")
    FAKE_RESULTS = requests.get("http://fakeurl.com/names")

        return FAKE_RESULTS

  • Mocking the same function across multiple tests and it leading to failure due to the function being a singleton.

@patch("requests.get")
def test_unittest_singleton(mock_request):
    """Example mocking using"""
    x_return_value = ["Leto Atreides"]
    mock_request.return_value = x_return_value
    results = get_dune_character()
    log.info(f"Results {results}")
    assert x_return_value == results


@pytest.mark.xfail
@patch("requests.get")
def test_unittest_singleton_second_call(mock_request):
    """ Example mocking singleton second call that should fail because singleton already loaded. """
    x_return_value = ["Paul Atreides", "Leto Atreides"]
    mock_request.return_value = x_return_value
    results = get_dune_character()
    assert x_return_value == results

The first test works because it's the first time you're setting the return_value for the mock. The issue is the second test is going to fail when it calls get_dune_characters if the function is a singleton. Note this is by design because the characters in Dune don't change the developer(me in this case lol) just needed to remember he made this design choice when writing his tests.

In order to make this work you must reload the module in between each test.

# You can use `autouse` here to make this happen automatically
@pytest.fixture(autouse=False)
def reload_module():
    import importlib
    import test_mocking_python
    importlib.reload(test_mocking_python)


@pytest.mark.parametrize("x_return_value", [
    (["Paul Atreides", "Leto Atreides"]),
    (["Sir Duncan Idaho"]),
    (["Lady Jessica"]),
    (["Feyd-Rautha Harkonnen"])
])
@patch("requests.get")
def test_unittest_singleton_reload(mock_request, reload_module, x_return_value):
    """ Example mocking singleton second call reload """
    mock_request.return_value = x_return_value
    results = get_dune_character()
    assert x_return_value == results

In the example above you can see I've added a fixture to force the module to reload therefore resetting the singleton variable in between each of the parameterized tests above.

If you've made it this far thanks for reading and I hope this helps someone else spend less time debugging a similar scenario.

Code from this blog entry can be found here .